# -*- coding:utf-8 -*-
"""
Classes to represent the default SQL aggregate functions
"""
# 该类代表缺省的sql中的聚合函数
import copy

from django.db.models.fields import IntegerField, FloatField

# Fake fields used to identify aggregate types in data-conversion operations.
ordinal_aggregate_field = IntegerField()            # 表示整型的数据类型
computed_aggregate_field = FloatField()             # 表示计算的float的数据类型


"""
    聚集函数处理的基础类
    被具体的聚集函数继承，实现具体的功能
"""
class Aggregate(object):
    """
        缺省的SQL聚集函数
    """
    is_ordinal = False                                  # 聚集函数的结果是int类型
    is_computed = False                                 # 聚集函数的结果是fload类型
    sql_template = '%(function)s(%(field)s)'            # 聚集函数的sql模板，如：count(table.column)

    """
        col----相关列

    """
    def __init__(self, col, source=None, is_summary=False, **extra):
        """
            1、实例化一个SQL的聚合
            2、参数介绍：
                col----是一个列，代表聚合的主题；可以是一个别名alias，或者tuple(table_name, column_name)
                source----底层字段或者聚合标示列的引用。如果聚集函数不是一个有序或者计算类型，这表明用于强制限定
                          聚集的输出类型
                extra----字典dict类型的额外data，用于聚集的定义；
            3、同样也会初始化类的一些变量：
                sql_function----SQL的聚集函数的函数名，比如：avg等；
                sql_template----字符串的模板，用于提供聚集函数拼装到SQL中；
                is_ordinal----一个boolean类型，表明聚集函数的输出是一个整数；
                is_computed-----一个boolean类型，表明该聚集函数的输出一个计算得到的float类型，比如，average
        """
        self.col = col                  # 聚集的主题
        self.source = source            #
        self.is_summary = is_summary
        self.extra = extra              # 额外的参数

        # Follow the chain of aggregate sources back until you find an
        # actual field, or an aggregate that forces a particular output
        # type. This type of this field will be used to coerce values
        # retrieved from the database.
        tmp = self

        while tmp and isinstance(tmp, Aggregate):
            if getattr(tmp, 'is_ordinal', False):
                tmp = ordinal_aggregate_field               # int类型的Field
            elif getattr(tmp, 'is_computed', False):
                tmp = computed_aggregate_field              # float类型的Field
            else:
                tmp = tmp.source

        self.field = tmp

    def relabeled_clone(self, change_map):
        clone = copy.copy(self)
        if isinstance(self.col, (list, tuple)):
            clone.col = (change_map.get(self.col[0], self.col[0]), self.col[1])
        return clone

    """
        返回一个聚集在SQL中的语法
    """
    def as_sql(self, qn, connection):
        "Return the aggregate, rendered as SQL with parameters."
        params = []

        # 处理得到field的name值
        if hasattr(self.col, 'as_sql'):
            field_name, params = self.col.as_sql(qn, connection)
        elif isinstance(self.col, (list, tuple)):
            field_name = '.'.join([qn(c) for c in self.col])
        else:
            field_name = self.col

        substitutions = {
            'function': self.sql_function,          # sql_function是聚集函数的函数，在派生类中被赋值
            'field': field_name
        }
        substitutions.update(self.extra)            # 利用额外的参数，更新map中的值，比如向其中增加distinct字段

        return self.sql_template % substitutions, params


# 以下为SQL中具体的聚合函数接口

"""
    avg的聚集函数
"""
class Avg(Aggregate):
    is_computed = True          # 计算的float数据类型
    sql_function = 'AVG'        # 聚集函数的函数名


"""
    count的聚集函数
"""
class Count(Aggregate):
    is_ordinal = True                                           # int的数据类型
    sql_function = 'COUNT'                                      # 聚集函数：COUNT
    sql_template = '%(function)s(%(distinct)s%(field)s)'        # 格式：COUNT（DISTINCT column_name）

    """
        col---相关的列，
        distinct---标识是否使用该属性distinct
    """
    def __init__(self, col, distinct=False, **extra):
        super(Count, self).__init__(col, distinct='DISTINCT ' if distinct else '', **extra)


"""
    max的聚集函数
"""
class Max(Aggregate):
    sql_function = 'MAX'            # 聚集函数名MAX


"""
    Min的聚集函数
"""
class Min(Aggregate):
    sql_function = 'MIN'            # 聚集函数名MIn


# STDDEV_SAMP功能
class StdDev(Aggregate):
    is_computed = True

    def __init__(self, col, sample=False, **extra):
        super(StdDev, self).__init__(col, **extra)
        self.sql_function = 'STDDEV_SAMP' if sample else 'STDDEV_POP'


"""
    SUM的聚集函数
"""
class Sum(Aggregate):
    sql_function = 'SUM'            # 聚集函数名SUM


class Variance(Aggregate):
    is_computed = True

    def __init__(self, col, sample=False, **extra):
        super(Variance, self).__init__(col, **extra)
        self.sql_function = 'VAR_SAMP' if sample else 'VAR_POP'
